package com.ihr360.payroll.model.dto.salary.meta.system;


import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ihr360.commons.model.type.FieldSource;
import com.ihr360.payroll.model.base.ISalaryField;
import com.ihr360.payroll.model.dto.salary.basecode.SalaryFieldCategory;
import com.ihr360.payroll.model.dto.salary.basecode.SalaryFieldType;
import com.ihr360.payroll.model.dto.salary.basecode.SalaryTaxType;
import com.ihr360.payroll.model.dto.salary.embeddable.SystemSalaryFieldValue;
import com.ihr360.payroll.model.dto.salary.superclass.AbstractSalaryField;
import com.ihr360.payroll.model.vo.SalaryFieldTypeVo;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.vladmihalcea.hibernate.type.json.JsonStringType;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import java.util.ArrayList;
import java.util.List;

/**
 * 薪酬字段元信息定义
 */
@Entity
@Cacheable
@TypeDefs({
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
//@EntityListeners(value = {CodeGeneratorHandler.class})
public class SystemSalaryField extends AbstractSalaryField<SystemSalaryFieldValue>
        implements ISalaryField<SystemSalaryFieldValue> {
    private static final long serialVersionUID = -2022818117927766910L;

    /**
     * 代码
     */
    @Column(unique = true, nullable = false, length = 32, updatable = false)
    private String code;

    /**
     * 薪资字段的标志，由于薪资计算中的引用标记（应该采用根据类型的序列号生成规则）
     */
    @Column(nullable = true, length = 40)
    //@CodeGenerator(bizModel = "")
    protected String fieldId;

    /**
     * 类别下排序序号
     */
//    @CodeGenerator(bizModel = "sys_salary_field_order", serialTmpl = "SERIALGEN(MAXID)", name = "系统薪资字段分类排序", categoryId = "SERIALID(categoryCode)")
    protected int typeIndex = 1;

    /**
     * 薪酬字段分类(大类)
     */
    @ManyToOne(fetch = FetchType.EAGER)
    private SalaryFieldCategory category;

    /**
     * 是否统计项
     */
    private boolean countField = false;

    /**
     * 员工收入计算规则是否可编辑
     */
    private boolean personalSalaryNumOpEditable = true;

    /**
     * 员工收入计算规则是否可见
     */
    private boolean personalSalaryNumOpVisible = true;

    /**
     * 公司成本计算规则是否可编辑
     */
    private boolean companyCostNumOpEditable = true;

    /**
     * 公司成本计算规则是否可见
     */
    private boolean companyCostNumOpVisible = true;

    /**
     * 承担方是否可编辑
     */
    private boolean payerEditable = true;

    /**
     * 承担方是否可见
     */
    private boolean payerVisible = true;

    /**
     * 实际承担方是否可编辑
     */
    private boolean actualPayerEditable = true;

    /**
     * 实际承担方是否可见
     */
    private boolean actualPayerVisible = true;

    /**
     * 可选缴税类型列表
     */
    @ManyToMany
    private List<SalaryTaxType> taxTypes = new ArrayList<>();

    /**
     * 缴税类型是否可编辑
     */
    private boolean taxTypeEditable = true;

    /**
     * 缴税类型是否可见
     */
    private boolean taxTypeVisible = true;

    /**
     * 字段值限制是否可编辑
     */
    private boolean valueMetaEditable = true;

    /**
     * 字段值限制是否可见
     */
    private boolean valueMetaVisible = true;

    /**
     * 字段取值方式是否可编辑
     */
    private boolean valueSourceEditable = true;

    /**
     * 字段取值方式是否可见
     */
    private boolean valueSourceVisible = true;

    /**
     * 是否可添加到员工薪资
     */
    private boolean showInStaffSalary = true;

    /**
     * 字段值限制
     */
    @Embedded
    protected SystemSalaryFieldValue valueMeta;

    @Column(columnDefinition = "bit(1) default 0")
    private boolean embedded;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public int getTypeIndex() {
        return typeIndex;
    }

    public void setTypeIndex(int typeIndex) {
        this.typeIndex = typeIndex;
    }

    public boolean isCountField() {
        return countField;
    }

    public void setCountField(boolean countField) {
        this.countField = countField;
    }

    @Override
    public SystemSalaryFieldValue getValueMeta() {
        return valueMeta;
    }

    @Override
    public void setValueMeta(SystemSalaryFieldValue valueMeta) {
        this.valueMeta = valueMeta;
    }

    public boolean isPersonalSalaryNumOpEditable() {
        return personalSalaryNumOpEditable;
    }

    public void setPersonalSalaryNumOpEditable(boolean personalSalaryNumOpEditable) {
        this.personalSalaryNumOpEditable = personalSalaryNumOpEditable;
    }

    public boolean isCompanyCostNumOpEditable() {
        return companyCostNumOpEditable;
    }

    public void setCompanyCostNumOpEditable(boolean companyCostNumOpEditable) {
        this.companyCostNumOpEditable = companyCostNumOpEditable;
    }

    public boolean isPayerEditable() {
        return payerEditable;
    }

    public void setPayerEditable(boolean payerEditable) {
        this.payerEditable = payerEditable;
    }

    public boolean isActualPayerEditable() {
        return actualPayerEditable;
    }

    public void setActualPayerEditable(boolean actualPayerEditable) {
        this.actualPayerEditable = actualPayerEditable;
    }

    public boolean isTaxTypeEditable() {
        return taxTypeEditable;
    }

    public void setTaxTypeEditable(boolean taxTypeEditable) {
        this.taxTypeEditable = taxTypeEditable;
    }

    public boolean isValueMetaEditable() {
        return valueMetaEditable;
    }

    public void setValueMetaEditable(boolean valueMetaEditable) {
        this.valueMetaEditable = valueMetaEditable;
    }

    public boolean isPersonalSalaryNumOpVisible() {
        return personalSalaryNumOpVisible;
    }

    public void setPersonalSalaryNumOpVisible(boolean personalSalaryNumOpVisible) {
        this.personalSalaryNumOpVisible = personalSalaryNumOpVisible;
    }

    public boolean isCompanyCostNumOpVisible() {
        return companyCostNumOpVisible;
    }

    public void setCompanyCostNumOpVisible(boolean companyCostNumOpVisible) {
        this.companyCostNumOpVisible = companyCostNumOpVisible;
    }

    public boolean isPayerVisible() {
        return payerVisible;
    }

    public void setPayerVisible(boolean payerVisible) {
        this.payerVisible = payerVisible;
    }

    public boolean isActualPayerVisible() {
        return actualPayerVisible;
    }

    public void setActualPayerVisible(boolean actualPayerVisible) {
        this.actualPayerVisible = actualPayerVisible;
    }

    public boolean isTaxTypeVisible() {
        return taxTypeVisible;
    }

    public void setTaxTypeVisible(boolean taxTypeVisible) {
        this.taxTypeVisible = taxTypeVisible;
    }

    public boolean isValueMetaVisible() {
        return valueMetaVisible;
    }

    public void setValueMetaVisible(boolean valueMetaVisible) {
        this.valueMetaVisible = valueMetaVisible;
    }

    public List<SalaryTaxType> getTaxTypes() {
        return taxTypes;
    }

    public void setTaxTypes(List<SalaryTaxType> taxTypes) {
        this.taxTypes = taxTypes;
    }

    public boolean isValueSourceEditable() {
        return valueSourceEditable;
    }

    public void setValueSourceEditable(boolean valueSourceEditable) {
        this.valueSourceEditable = valueSourceEditable;
    }

    public boolean isValueSourceVisible() {
        return valueSourceVisible;
    }

    public void setValueSourceVisible(boolean valueSourceVisible) {
        this.valueSourceVisible = valueSourceVisible;
    }

    public SalaryFieldCategory getRequiredCategory() {
        return this.category == null ? (this.type == null ? null : this.type.getCategory()) : category;
    }

    public SalaryFieldCategory getCategory() {
        return this.category;
    }

    public void setCategory(SalaryFieldCategory category) {
        this.category = category;
    }


    public boolean isShowInStaffSalary() {
        return showInStaffSalary;
    }

    public void setShowInStaffSalary(boolean showInStaffSalary) {
        this.showInStaffSalary = showInStaffSalary;
    }

    @Override
    public FieldSource getSource() {
        if (valueMeta != null) {
            return valueMeta.getDefaultSource();
        }
        return FieldSource.INPUT;
    }

    @JsonIgnore
    public SalaryFieldTypeVo getTypeVo() {
        SalaryFieldType type = getType();
        return new SalaryFieldTypeVo(type.getId(), type.getCode(), type.isSalaryTaxTypeRequired(),
                type.isCustomizable(), type.getCompanycostop(), type.getPersonalsalaryop(), type.getFieldTaxType());
    }

    public String getCategoryCode() {
        return getRequiredCategory().getCode();
    }
}